﻿using System;
using Firestarter.Test.Base;
using FireStarterModeller.BO;
using FireStarterModeller.Test.BO.Fakes;
using Habanero.BO;
using Habanero.Test.Structure;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarterModeller.Test.BO
{
    [TestFixture]
    public class TestSolutionRenamer
    {
        #region Setup/Teardown

        [TestFixtureSetUp]
        public void SetupFixture()
        {
            TestUtilsDomain.SetupFixture();
        }

        [SetUp]
        public virtual void SetupTest()
        {
            //-------------------------------------------------------------------------------------
            // You can choose here whether to run against a database or whether to use an in-memory
            // database for all the tests, which runs quickly. It doesn't however check that
            // your database has the correct structure, which is partly the purpose of these tests.
            // The generated tests do already use an in-memory database where possible.
            // In your custom tests, you can set them to use an in-memory database by copying the
            // line to the first line of your test.
            //-------------------------------------------------------------------------------------
            //BORegistry.DataAccessor = new DataAccessorDB();
            BORegistry.DataAccessor = new DataAccessorInMemory();
            TestUtilsDomain.SetupTest();
        }

        [TearDown]
        public virtual void TearDownTest()
        {
        }

        #endregion

        [Test]
        public void Test_DefaaultAssemblyBOSuffix_ShouldBeBO()
        {
            //---------------Set up test pack-------------------
            
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            var defaultAssemblyBOSuffix = SolutionRenamer.DefaultAssemblyBOSuffix;
            //---------------Test Result -----------------------
            Assert.AreEqual(".BO", defaultAssemblyBOSuffix);
        }
        [Test]
        public void Test_Construct_WhenRelationshipPropertyNull_ShouldRaiseError()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            try
            {
                new SolutionRenamer(null);
                Assert.Fail("expected ArgumentNullException");
            }
                //---------------Test Result -----------------------
            catch (ArgumentNullException ex)
            {
                StringAssert.Contains("Value cannot be null", ex.Message);
                StringAssert.Contains("solution", ex.ParamName);
            }
        }

        [Test]
        public void Test_Construct_ShouldSetSolution()
        {
            //---------------Set up test pack-------------------
            var mockDMSolution = MockRepository.GenerateMock<DMSolution>(ConstructForFakes.True);
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            var solutionRenamer = new SolutionRenamer(mockDMSolution);
            //---------------Test Result -----------------------
            Assert.AreSame(mockDMSolution, solutionRenamer.Solution);
        }
        [Test]
        public void Test_RenameToStandardNames_WhenOneClass_ShouldCallRenameClass()
        {
            //---------------Set up test pack-------------------
            FakeDMSolution mockDMSolution = GetMockDMSolution();
            var mockDMClass = MockRepository.GenerateMock<FakeDMClass>();
            mockDMSolution.AllClasses.Add(mockDMClass);
            var solutionRenamer = new SolutionRenamer(mockDMSolution);
            //---------------Assert Precondition----------------
            Assert.Contains(mockDMClass, mockDMSolution.AllClasses);
            mockDMClass.AssertWasNotCalled(@class => @class.RenameClass());
            //---------------Execute Test ----------------------
            solutionRenamer.RenameAllClassesToStandardNames();
            //---------------Test Result -----------------------
            mockDMClass.AssertWasCalled(@class => @class.RenameClass());
        }    
        [Test]
        public void Test_RenameToStandardNames_WhenTwoClass_ShouldCallRenameClass()
        {
            //---------------Set up test pack-------------------
            FakeDMSolution mockDMSolution = GetMockDMSolution();
            var mockDMClass = MockRepository.GenerateMock<FakeDMClass>();
            var mockDMClass2 = MockRepository.GenerateMock<FakeDMClass>();
            mockDMSolution.AllClasses.Add(mockDMClass);
            mockDMSolution.AllClasses.Add(mockDMClass2);
            var solutionRenamer = new SolutionRenamer(mockDMSolution);
            //---------------Assert Precondition----------------
            Assert.Contains(mockDMClass, mockDMSolution.AllClasses);
            Assert.Contains(mockDMClass2, mockDMSolution.AllClasses);
            mockDMClass.AssertWasNotCalled(@class => @class.RenameClass());
            mockDMClass2.AssertWasNotCalled(@class => @class.RenameClass());
            //---------------Execute Test ----------------------
            solutionRenamer.RenameAllClassesToStandardNames();
            //---------------Test Result -----------------------
            mockDMClass.AssertWasCalled(@class => @class.RenameClass());
            mockDMClass2.AssertWasCalled(@class => @class.RenameClass());
        }

        [Test]
        public void Test_RenameSolution_ShouldRenameSolution()
        {
            //---------------Set up test pack-------------------
            var solution = MockRepository.GenerateStub<FakeDMSolution>();
            var initialSolutionName = GetRandomString();
            solution.SolutionName = initialSolutionName;
            var solutionRenamer = new SolutionRenamer(solution);
            var expectedSolutionName = GetRandomString();

            //---------------Assert Precondition----------------
            Assert.AreSame(solution, solutionRenamer.Solution);
            Assert.AreEqual(initialSolutionName, solution.SolutionName);
            //---------------Execute Test ----------------------
            solutionRenamer.RenameSolution(expectedSolutionName);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedSolutionName, solution.SolutionName);
        }
        [Test]
        public void Test_RenameSolution_WhenDefaultAssemblyNull_ShouldRenameSolution()
        {
            //---------------Set up test pack-------------------
            var solution = MockRepository.GenerateStub<FakeDMSolution>();
            var initialSolutionName = GetRandomString();
            solution.SolutionName = initialSolutionName;
            var solutionRenamer = new SolutionRenamer(solution);
            var expectedSolutionName = GetRandomString();

            //---------------Assert Precondition----------------
            Assert.AreEqual(initialSolutionName, solution.SolutionName);
            Assert.IsNull(solution.DefaultAssembly);
            //---------------Execute Test ----------------------
            solutionRenamer.RenameSolution(expectedSolutionName);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedSolutionName, solution.SolutionName);
        }

        [Test]
        public void Test_RenameSolution_WhenHasDefaultAssembly_AndAssemblyNameIsSolutionName_BO_ShouldRenameDefaultAssembly()
        {
            //---------------Set up test pack-------------------
            var solution = MockRepository.GenerateStub<FakeDMSolution>();
            solution.SolutionName = GetRandomString();
            solution.DefaultAssembly = new DMAssembly(solution.SolutionName + ".BO");

            var solutionRenamer = new SolutionRenamer(solution);

            //---------------Assert Precondition----------------
            Assert.AreSame(solution, solutionRenamer.Solution);
            var defaultAssembly = solution.DefaultAssembly;
            Assert.IsNotNull(defaultAssembly);
            Assert.IsTrue(defaultAssembly.AssemblyName.StartsWith(solution.SolutionName));

            //---------------Execute Test ----------------------
            var expectedSolutionName = GetRandomString();
            solutionRenamer.RenameSolution(expectedSolutionName);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedSolutionName, solution.SolutionName);
            Assert.AreEqual(expectedSolutionName + ".BO", solution.DefaultAssembly.AssemblyName);
        }
        [Test]
        public void Test_RenameSolution_WhenHasDefaultAssembly_AndAssemblyNameNotSolutionName_BO_ShouldRenameDefaultAssembly()
        {
            //---------------Set up test pack-------------------
            var solution = MockRepository.GenerateStub<FakeDMSolution>();
            solution.SolutionName = GetRandomString();
            var initialAssemblyName = GetRandomString();
            solution.DefaultAssembly = new DMAssembly(initialAssemblyName);
          
            var solutionRenamer = new SolutionRenamer(solution);

            //---------------Assert Precondition----------------
            Assert.AreSame(solution, solutionRenamer.Solution);
            var defaultAssembly = solution.DefaultAssembly;
            Assert.IsNotNull(defaultAssembly);
            Assert.IsFalse(defaultAssembly.AssemblyName.StartsWith(solution.SolutionName));

            //---------------Execute Test ----------------------
            var expectedSolutionName = GetRandomString();
            solutionRenamer.RenameSolution(expectedSolutionName);
            //---------------Test Result -----------------------
            Assert.AreNotEqual(initialAssemblyName, solution.DefaultAssembly.AssemblyName, "Should rename assembly");
            Assert.AreEqual(expectedSolutionName + ".BO", solution.DefaultAssembly.AssemblyName, "Should rename assembly");
        }
        /// <summary>
        /// In the user interface the defaultBOEditor updates the Solution.SolutionName as soon as the 
        /// solutionName is edited in the text box.
        /// The renamed solution therefore needs to rename the default assembly
        /// from the previous solution name to the new solution name
        /// </summary>
        [Test]
        public void Test_RenameSolution_WhenSolutionNameAlreadyChangedButAssemblyNameNotChanged_ShouldRenameDefaultAssembly()
        {
            //---------------Set up test pack-------------------
            var solution = MockRepository.GenerateStub<FakeDMSolution>();
            var initialSolutionName = GetRandomString();
            solution.SolutionName = initialSolutionName;
            solution.DefaultAssembly = new DMAssembly(initialSolutionName + ".BO");

            var solutionRenamer = new SolutionRenamer(solution);

            //---------------Assert Precondition----------------
            Assert.AreSame(solution, solutionRenamer.Solution);
            var defaultAssembly = solution.DefaultAssembly;
            Assert.IsNotNull(defaultAssembly);
            Assert.IsTrue(defaultAssembly.AssemblyName.StartsWith(solution.SolutionName));

            //---------------Execute Test ----------------------
            var expectedSolutionName = GetRandomString();
            solution.SolutionName = expectedSolutionName;
            solutionRenamer.RenameSolution(expectedSolutionName);
            //---------------Test Result -----------------------
            Assert.AreEqual(expectedSolutionName, solution.SolutionName);
            Assert.AreEqual(expectedSolutionName + ".BO", solution.DefaultAssembly.AssemblyName);
        }
        private string GetRandomString()
        {
            return RandomValueGen.GetRandomString();
        }

        private static FakeDMSolution GetMockDMSolution()
        {
            var mockDMSolution = MockRepository.GenerateMock<FakeDMSolution>();
            mockDMSolution.Stub(solution => solution.AllClasses).Return(new FakeBusinessObjectCollection<DMClass>());
            return mockDMSolution;
        }
 
    }
}